<script setup lang="ts">
const props = withDefaults(defineProps<{
  state: 'normal' | 'loading' | 'success'
  tipText: string
  loadingTipText?: string
  successTipText?: string
}>(), {
  loadingTipText: '加载中...',
  successTipText: '成功',
})

const emit = defineEmits(['done'])

// 是否处于滑动中
const isDraging = ref(false)
// 起始位置
const startX = ref<number>()
// 开始时间
const startTime = ref<number>()
// 滑动的偏移值
const offset = ref(0)

watch(() => props.state, (newVal) => {
  if (newVal === 'normal')
    offset.value = 0
  else
    offset.value = 220
})

// 提示文字的不透明度
const tipTextOpacity = computed(() => {
  return 1 - offset.value / 220 * 1.3
})
// 绿色背景的不透明度
const successBgOpacity = computed(() => {
  return offset.value / 220 * 1.3
})

/**
 * @description 处理滑动事件。
 * 若 startX 为 undefined，意味着滑动未开始，设置开始位置和开始时间，
 * 否则处于滑动中，在向右滑动的情况下，更新 offset 值。
 */
function handleDrag(e: any) {
  if (!startX.value) {
    isDraging.value = true
    startX.value = e.touches[0].pageX
    startTime.value = Date.now()
  }
  else {
    const currentX = e.touches[0].pageX
    if (currentX < startX.value!)
      return
    offset.value = Math.min(currentX - startX.value!, 220)
  }
}

/**
 * @description 处理滑动结束事件。
 * 根据时间和距离计算出滑动速度，根据滑动速度和滑动距离阈值判定滑动是否成功。
 */
function handleEndDrag() {
  if (!startTime.value)
    return

  isDraging.value = false
  const endTime = Date.now()
  const duration = endTime - startTime.value
  const velocity = Math.abs(offset.value / duration)

  const threshold = 150

  if (offset.value >= threshold && velocity >= 0.1) {
    offset.value = 220
    emit('done')
  }
  else {
    offset.value = 0
  }

  startX.value = undefined
  startTime.value = undefined
}
</script>

<template>
  <view
    class="relative h-120rpx w-full flex items-center justify-center rounded-10rpx from-#549FF7 to-#3F8BF6 bg-gradient-to-r"
    @touchmove="handleDrag"
    @touchend="handleEndDrag"
  >
    <view
      class="absolute bottom-0 left-0 right-0 top-0 rounded-10rpx bg-emerald-500"
      :style="{ opacity: successBgOpacity }"
    />
    <view class="relative z-10">
      <view v-show="state === 'normal'" class="flex items-center justify-center">
        <image
          class="h-40rpx w-38rpx"
          :class="!isDraging ? 'transition-all duration-300 ease-in-out' : ''"
          src="@/static/images/chevron_double_white.png"
          :style="{
            transform: `translateX(${offset}px)`,
            opacity: `${tipTextOpacity}`,
          }"
        />
        <Spacer w="40" />
        <view
          class="text-36rpx text-white leading-36rpx"
          :class="!isDraging ? 'transition-all duration-300 ease-in-out' : ''"
          :style="{ opacity: `${tipTextOpacity}` }"
        >
          {{ props.tipText }}
        </view>
      </view>
      <view v-show="state === 'loading'" class="flex items-center justify-center">
        <image
          class="h-40rpx w-40rpx animate-spin"
          src="@/static/images/loading.png"
        />
        <Spacer w="20" />
        <view class="text-36rpx text-white font-medium leading-36rpx">
          {{ loadingTipText }}
        </view>
      </view>
      <view v-show="state === 'success'" class="flex items-center justify-center">
        <image
          class="h-40rpx w-40rpx"
          src="@/static/images/checkmark_circle_white.png"
        />
        <Spacer w="20" />
        <view class="text-36rpx text-white font-medium leading-36rpx">
          {{ successTipText }}
        </view>
      </view>
    </view>
  </view>
</template>
